package trigger

import (
	"database/sql"
	"log"
	"strconv"
	"strings"
	"time"
	"xin-job/admin/abiz"
	"xin-job/admin/dao"
	"xin-job/admin/dao/model"
	"xin-job/admin/router"
	"xin-job/core/biz"
	"xin-job/core/utils"
)

// trigger 触发任务
// jobId 任务ID
// triggerType 触发的类型
// failRetryCount 失败重试次数
// executorShardingParam 分片参数
// executorShardingParam 执行器方法参数
// addressList 执行器的地址列表
func AddTrigger(jobId int,
	triggerType string,
	failRetryCount int,
	executorShardingParam string,
	executorParam string,
	addressList string) {

	go func() {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("trigger err %v\n", err)
			}
		}()

		result := biz.Return[string]{
			Code: 500,
		}

		job := dao.LoadJobInfoById(jobId)
		group := dao.LoadGroup(job.JobGroup)

		// Log
		jobLog := model.XxlJobLog{
			JobGroup: group.Id,
			JobId:    job.Id,
			TriggerTime: sql.NullTime{
				Time:  time.Now(),
				Valid: true,
			},
		}
		dao.SaveLog(&jobLog)

		if group.AddressList == "" {
			result.Code = 500
			result.Msg = "调度失败：执行器地址为空"

			updateLog(&jobLog, &result, triggerType, "", job, group)
			return
		}

		// 分片广播
		// 分片广播调度中心实现其实非常简单。只需要将任务平均的触发到每个执行器即可。
		// 真正数据分片，是需要执行器根据，当前分片数以及分片总数，自行进行数据拆分的。

		// 当前分片数：i
		// 分片总数：执行器个数
		if router.SHARDING_BROADCAST == job.ExecutorBlockStrategy {
			for i := range group.AddressList {
				processTrigger(group, job, &jobLog, triggerType, i, len(group.AddressList))
			}
		} else {
			processTrigger(group, job, &jobLog, triggerType, 0, 1)
		}

	}()
}

func processTrigger(group *model.XxlJobGroup, job *model.XxlJobInfo, jobLog *model.XxlJobLog, triggerType string, index int, total int) {
	result := biz.Return[string]{
		Code: 500,
	}

	// 获取路由
	route := router.GetRouter(job.ExecutorBlockStrategy)
	address, err := route.Router(job.Id, group.GetRegistryList())
	if err != nil {
		result.Msg = "路由地址失败"

		updateLog(jobLog, &result, triggerType, route.GetTitle(), job, group)
		return
	}

	p := biz.TriggerParam{
		JobId:                 job.Id,
		ExecutorHandler:       job.ExecutorHandler,
		ExecutorParams:        job.ExecutorParam,
		ExecutorBlockStrategy: job.ExecutorBlockStrategy,
		ExecutorTimeout:       job.ExecutorTimeout,
		LogId:                 jobLog.Id,
		LogDateTime:           jobLog.TriggerTime.Time.UnixMilli(),
		GlueType:              job.GlueType,
		GlueSource:            job.GlueSource,
		GlueUpdatetime:        job.GlueUpdatetime.UnixMilli(),
		BroadcastIndex:        index,
		BroadcastTotal:        total,
	}

	abiz.GetExecutorBizClient().ClientAddressUrl = address
	result = abiz.GetExecutorBizClient().Run(&p)

	// update db
	jobLog.ExecutorAddress = address
	jobLog.ExecutorHandler = job.ExecutorHandler
	jobLog.ExecutorParam = job.ExecutorParam
	jobLog.ExecutorShardingParam = "" // TODO 分片
	jobLog.ExecutorFailRetryCount = 0 // TODO 重试

	updateLog(jobLog, &result, triggerType, route.GetTitle(), job, group)
}

func updateLog(jobLog *model.XxlJobLog, result *biz.Return[string],
	triggerType, routerTitle string, job *model.XxlJobInfo, group *model.XxlJobGroup) {

	jobLog.TriggerCode = result.Code
	addressType := "自动注册"
	if group.AddressType != 0 {
		addressType = "手动录入"
	}
	executorTimeout := strconv.FormatInt(int64(job.ExecutorTimeout), 10)
	jobLog.TriggerMsg = writeMsg(triggerType, addressType, group.AddressList, routerTitle,
		job.ExecutorBlockStrategy, executorTimeout, result.Msg)
	dao.UpdateLog(jobLog)
}

func writeMsg(triggerType, addressType, addressList,
	routerTitle, executorBlockStrategy,
	executorTimeout, resultMsg string) string {

	var msgBuilder strings.Builder
	msgBuilder.WriteString("任务触发类型:")
	msgBuilder.WriteString(triggerType)

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("调度机器:")
	ip, _ := utils.GetIP()
	msgBuilder.WriteString(ip)

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("执行器-注册方式:")
	msgBuilder.WriteString(addressType)

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("执行器-地址列表:")
	msgBuilder.WriteString(addressList)

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("路由策略:")
	msgBuilder.WriteString(routerTitle) // TODO 拼接分片

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("阻塞处理策略:")
	msgBuilder.WriteString(executorBlockStrategy) // TODO enums to title

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("任务超时时间:")
	msgBuilder.WriteString(executorTimeout)

	msgBuilder.WriteString("<br>")
	msgBuilder.WriteString("失败重试次数:")
	msgBuilder.WriteString("0")

	msgBuilder.WriteString(`<br><br><span style="color:#00c0ef;" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>`)
	msgBuilder.WriteString(resultMsg)
	msgBuilder.WriteString("<br><br>")

	return msgBuilder.String()
}
